# character sets
[identifier_schars a-zA-Z_
[identifier_chars a-zA-Z0-9_
[num_chars_start 0-9
[num_chars 0-9
[octal_chars 0-7
[hex_chars 0-9a-fA-F
[float_chars_start 0-9.\-\+
[float_chars 0-9.eE
[float_chars_start 0-9.\-\+
[ws \ \t\r\n
[endl \r\n
# single-character transitions can't be inverted yet, but csets can 
[slash \\
[rbracket ]
[star *
[dquote "



# keywords
{__peg_parser__ :cat=Keyword |identifier_chars>LST_identifier
{and :cat=Keyword |identifier_chars>LST_identifier
{break :cat=Keyword |identifier_chars>LST_identifier
{do :cat=Keyword |identifier_chars>LST_identifier
{else :cat=Keyword |identifier_chars>LST_identifier
{elseif :cat=Keyword |identifier_chars>LST_identifier
{end :cat=Keyword |identifier_chars>LST_identifier
{false :cat=Keyword |identifier_chars>LST_identifier
{for :cat=Keyword |identifier_chars>LST_identifier
{function :cat=Keyword |identifier_chars>LST_identifier
{if :cat=Keyword |identifier_chars>LST_identifier
{in :cat=Keyword |identifier_chars>LST_identifier
{local :cat=Keyword |identifier_chars>LST_identifier
{nil :cat=Keyword |identifier_chars>LST_identifier
{not :cat=Keyword |identifier_chars>LST_identifier
{or :cat=Keyword |identifier_chars>LST_identifier
{repeat :cat=Keyword |identifier_chars>LST_identifier
{return :cat=Keyword |identifier_chars>LST_identifier
{then :cat=Keyword |identifier_chars>LST_identifier
{true :cat=Keyword |identifier_chars>LST_identifier
{until :cat=Keyword |identifier_chars>LST_identifier
{while :cat=Keyword |identifier_chars>LST_identifier



# operators and punctuation
{+ :cat=Operator
{- :cat=Operator
:LST_NULL___dash @->LST_sl_comment_probe_1
{/ :cat=Operator
{* :cat=Operator
{% :cat=Operator
{^ :cat=Operator
{# :cat=Operator
{= :cat=Operator
{> :cat=Operator
{< :cat=Operator
{=< :cat=Operator
{=> :cat=Operator
{== :cat=Operator
{~= :cat=Operator

{( :cat=punct
{) :cat=punct
{[ :cat=punct
{] :cat=punct
{{ :cat=punct
{} :cat=punct

{, :cat=Operator
{; :cat=punct
{. :cat=Operator +num_chars>LST_float
{.. :cat=Operator 
{... :cat=Operator 
{: :cat=Operator


# mark some terminal states
&LST_float :cat=Number
&LST_probenum :cat=Number
&LST_intnum :cat=Number
&LST_octalnum :cat=Number
&LST_hexnum :cat=Number
&LST_identifier :cat=Identifier
&LST_float_exp :cat=Number

# all other identifiers
# + is transition on a character set
:LST_identifier +identifier_chars>LST_identifier
:LST_NULL +identifier_schars>LST_identifier

# ignore whitespace
:LST_NULL +ws>LST_ws
:LST_ws +ws>LST_ws
:LST_ws @\r=LST_ws
:LST_ws @\n=LST_ws
:LST_ws !+ws~LST_ws
&LST_ws :cat=Whitespace

# double-quote strings
# @ is a single-char transition
:LST_string @">LST_string_end
:LST_NULL @">LST_string_q
#:LST_string_end @:=LST_obj_key
&LST_string_end :cat=String
:LST_string @\\>LST_string_esc
:LST_string !+slash>LST_string
:LST_string_esc >LST_string
:LST_string @\r~LST_string_line_error
:LST_string @\n~LST_string_line_error
:LST_string_esc @\r~LST_string_line_error
:LST_string_esc @\n~LST_string_line_error
:LST_ml_string @\\>LST_ml_string_esc
:LST_ml_string @">LST_ml_string_q
:LST_ml_string !+slash>LST_ml_string
:LST_ml_string_esc >LST_ml_string
:LST_string_q !+dquote>LST_string
:LST_string_q @">LST_string_qq
:LST_string_qq !+dquote~LST_string_end
:LST_string_qq @">LST_ml_string
:LST_ml_string_q !+dquote>LST_ml_string
:LST_ml_string_q @">LST_ml_string_qq
:LST_ml_string_qq !+dquote>LST_ml_string
:LST_ml_string_qq @">LST_string_end

# &LST_obj_key :cat=Label

# single-quote strings
:LST_sq_string @'>LST_sq_string_end
#:LST_sq_string_end @:=LST_obj_key
:LST_NULL @'>LST_sq_string
&LST_sq_string_end :cat=String
:LST_sq_string @\\>LST_sq_string_esc
:LST_sq_string !+slash>LST_sq_string
:LST_sq_string_esc >LST_sq_string
:LST_sq_string @\r~LST_string_line_error
:LST_sq_string @\n~LST_string_line_error
:LST_sq_string_esc @\r~LST_string_line_error
:LST_sq_string_esc @\n~LST_string_line_error

&LST_string_line_error :cat=Error


# numbers
:LST_NULL @0>LST_probenum
:LST_NULL @1>LST_intnum
:LST_NULL @2>LST_intnum
:LST_NULL @3>LST_intnum
:LST_NULL @4>LST_intnum
:LST_NULL @5>LST_intnum
:LST_NULL @6>LST_intnum
:LST_NULL @7>LST_intnum
:LST_NULL @8>LST_intnum
:LST_NULL @9>LST_intnum

:LST_probenum @.>LST_float
:LST_probenum @x>LST_hexnum
:LST_probenum @X>LST_hexnum
#:LST_probenum @:=LST_obj_key
:LST_probefixed @x>LST_hexnum
:LST_probefixed @X>LST_hexnum
#:LST_probefixed @:=LST_obj_key
:LST_probenum +num_chars>LST_octalnum
:LST_probefixed +num_chars>LST_octalnum
:LST_intnum @.>LST_float
:LST_intnum +num_chars>LST_intnum
#:LST_intnum @:=LST_obj_key
:LST_octalnum +octal_chars>LST_octalnum
#:LST_octalnum @:=LST_obj_key
:LST_hexnum +hex_chars>LST_hexnum
#:LST_hexnum @:=LST_obj_key

:LST_float @.>LST_INVALID
:LST_float +num_chars>LST_float
:LST_float @e>LST_float_exp_start
:LST_float @E>LST_float_exp_start
:LST_float @d=LST_float
:LST_float @f=LST_float
:LST_float_exp_start +num_chars>LST_float_exp
:LST_float_exp_start @->LST_float_exp
:LST_float_exp_start @+>LST_float_exp
:LST_float_exp +num_chars>LST_float_exp
:LST_float_exp @d=LST_float
:LST_float_exp @f=LST_float

# comments
# ! inverts a character set
# = finishes a token, including the character tested
# ~ finishes a token but does not consume the character tested
:LST_sl_comment_probe_1 @[>LST_sl_comment_probe_2
:LST_sl_comment_probe_1 !+rbracket>LST_sl_comment
:LST_sl_comment_probe_2 @[>LST_ml_comment
:LST_sl_comment_probe_2 !+rbracket>LST_sl_comment
&LST_sl_comment :cat=Comment :type=CommentSingle
:LST_sl_comment >LST_sl_comment
:LST_sl_comment @\r~LST_sl_comment
:LST_sl_comment @\n~LST_sl_comment

&LST_ml_comment :cat=Comment :type=CommentMulti
:LST_ml_comment @]>LST_ml_comment_end_1
:LST_ml_comment !+rbracket>LST_ml_comment
:LST_ml_comment_end_1 @]=LST_ml_comment
:LST_ml_comment_end_1 !+rbracket>LST_ml_comment


